package com.seguriapp.complaints.gwt.server;

import static com.google.common.collect.Lists.newArrayList;

import java.util.List;

import net.customware.gwt.dispatch.server.ExecutionContext;
import net.customware.gwt.dispatch.shared.DispatchException;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.restlet.resource.ClientResource;

import com.seguriapp.common.config.GlobalConfigLoader;
import com.seguriapp.common.gwt.server.AbstractSeguriAppHandler;
import com.seguriapp.common.security.SeguriAppSession;
import com.seguriapp.common.security.SeguriAppUser;
import com.seguriapp.common.security.SeguriAppSession.Key;
import com.seguriapp.complaints.gwt.shared.GetComplaintsDataAction;
import com.seguriapp.complaints.gwt.shared.GetComplaintsDataResult;
import com.seguriapp.entities.Complaint;
import com.seguriapp.entities.CrimeCategory;
import com.seguriapp.entities.SeguriAppEntity;
import com.seguriapp.entities.User;
import com.seguriapp.util.Util;

public class GetComplaintsDataHandler extends AbstractSeguriAppHandler<GetComplaintsDataAction, GetComplaintsDataResult> {

  private static final Logger LOGGER = Logger.getLogger(GetComplaintsDataHandler.class);

  public Class<GetComplaintsDataAction> getActionType() {
    return GetComplaintsDataAction.class;
  }

  public GetComplaintsDataResult execute(final GetComplaintsDataAction action, final ExecutionContext context) throws DispatchException {
    LOGGER.info(SeguriAppUser.getSeguriAppSecureUser());
    final GetComplaintsDataResult result = new GetComplaintsDataResult();
    try {
      final String url = GlobalConfigLoader.getInstance().getGlobalConfig().getBackEndUrl()
          .concat(GlobalConfigLoader.getInstance().getGlobalConfig().getComplaintList());
      final ClientResource resource = new ClientResource(url);
      final String complaintListJs = resource.post(convertDataToJsonString(action)).getText();
      LOGGER.info("Data received : \n" + complaintListJs);
      result.setComplaintsList(getJsonDataFromString(complaintListJs));
      result.setCurrentPage(action.getPage());
      result.setMaxPages(GlobalConfigLoader.getInstance().getGlobalConfig().getMaxPages());
      result.setTotalPages(getJsonTotalPages(complaintListJs));
    } catch (Exception e) {
      LOGGER.error("Error al obtener las denuncias", e);
    }
    return result;
  }

  private String convertDataToJsonString(final GetComplaintsDataAction action) {
    final JSONObject obj = new JSONObject();
    try {
      obj.put("startDate", Util.parseDateToString(action.getStartDate()));
      obj.put("endDate", Util.parseDateToString(action.getEndDate()));
      obj.put("latitude", action.getLatitude());
      obj.put("longitude", action.getLongitude());
      obj.put("names", action.getNames());
      obj.put("distance", action.getDistance());
      obj.put("policeStationId", action.getPoliceStationId());
      obj.put("searchByPolStation", action.isSearchByPolStation());
      obj.put("page", action.getPage());
      obj.put("pageSize", GlobalConfigLoader.getInstance().getGlobalConfig().getPageSize());
      obj.put("ascending", action.isAscending());
      obj.put("columnSort", action.getColumnSort());
      final User user = SeguriAppUser.getSeguriAppSecureUser() != null ? SeguriAppUser.getSeguriAppSecureUser().getSeguriAppUser() : null;
      if (user != null) {
        obj.put("userId", user.getId());
      }
    } catch (JSONException e) {
      LOGGER.error("Error al convertir parametros de busqueda a json", e);
    }
    LOGGER.info("Sending Data : \n" + obj.toString());
    return obj.toString();
  }

  private long getJsonTotalPages(final String complaintListJs) {
    long totalPages = 0;
    final JSONObject root = JSONObject.fromObject(complaintListJs);
    if (root.has("totalPages")) {
      totalPages = root.getLong("totalPages");
    }
    return totalPages;
  }

  private List<Complaint> getJsonDataFromString(final String complaintListJs) {
    final SeguriAppSession session = SeguriAppUser.getSeguriAppSecureUser() != null ? SeguriAppUser.getSeguriAppSecureUser().getSeguriAppSession() : null;
    final List<Complaint> complaintsList = newArrayList();
    final JSONObject root = JSONObject.fromObject(complaintListJs);
    JSONArray dataArray = null;
    JSONObject jo = null;
    if (root.has("complaints")) {
      dataArray = root.getJSONArray("complaints");
      if (dataArray != null) {
        final Long lastComplaintId = (Long) session.get(Key.LastComplaintId);
        Long complaintId = lastComplaintId != null ? lastComplaintId : 0L;
        for (int i = 0; i < dataArray.size(); i++) {
          jo = dataArray.getJSONObject(i);
          final Complaint complaint = processjSONObject(jo);
          complaintsList.add(complaint);
          if (complaint.getId().compareTo(complaintId) > 0) {
            complaintId = complaint.getId();
          }
          if (lastComplaintId != null && complaint.getId().compareTo(lastComplaintId) > 0) {
            complaint.setNewComplaint(true);
          }
        }
        if (lastComplaintId == null || (lastComplaintId != null && complaintId.compareTo(lastComplaintId) > 0)) {
          session.put(Key.LastComplaintId, complaintId);
        }
      }
    }
    LOGGER.info("Last Complaint ID : " + session.get(Key.LastComplaintId));
    return complaintsList;
  }

  private Complaint processjSONObject(final JSONObject jo) {
    if (jo.has("id") && jo.has("crimeDate") && jo.has("dni") && jo.has("names") && jo.has("lastNames") && jo.has("crimelatitude")
        && jo.has("crimelongitude") && jo.has("category")) {
      final Complaint complaint = new Complaint();
      complaint.setId(jo.getLong("id"));
      complaint.setDni(jo.getString("dni"));
      complaint.setLastNames(jo.getString("lastNames"));
      complaint.setNames(jo.getString("names"));
      complaint.setPhone(jo.getString("phone"));
      complaint.setCrimeDate(Util.parseStringToDate(jo.getString("crimeDate")));
      complaint.setCrimeLatitude(jo.getDouble("crimelatitude"));
      complaint.setCrimeLongitude(jo.getDouble("crimelongitude"));
      complaint.setMapVisivility(jo.getBoolean("mapVisivility"));
      complaint.setAddress(jo.getString("address"));
      complaint.setEmail(jo.getString("email"));
      complaint.setDescription(jo.getString("description"));

      final JSONObject crimeCategoryJson = jo.getJSONObject("category");
      final CrimeCategory crimeCategory = new CrimeCategory();
      crimeCategory.setId(crimeCategoryJson.getLong("id"));
      crimeCategory.setName(crimeCategoryJson.getString("name"));
      crimeCategory.setDescription(crimeCategoryJson.getString("description"));
      complaint.setCategory(crimeCategory);

      final JSONObject policeStationJson = jo.getJSONObject("entity");
      final SeguriAppEntity policeStation = new SeguriAppEntity();
      policeStation.setId(policeStationJson.getLong("id"));
      policeStation.setTitle(policeStationJson.getString("title"));
      complaint.setPoliceStation(policeStation);
      return complaint;
    }
    return null;
  }

}
